package test.progenies.ecg.asm31.arrayvariables.bidimensional;

import static org.junit.Assert.assertNotNull;

import org.junit.Before;
import org.objectweb.asm.Opcodes;

import com.progenies.ecg.generator.ClassGenerator;
import com.progenies.ecg.generator.ClassGeneratorFactory;
import com.progenies.ecg.model.ClassObject;
import com.progenies.ecg.model.ConstructorObject;
import com.progenies.ecg.model.FieldObject;
import com.progenies.ecg.model.ParameterObject;
import com.progenies.ecg.model.codeparts.lines.LineFactory;

public abstract class BaseTestLocalArrayVariables {

	
	protected ClassGenerator clsGenerator;
	private static int counter = 0;

	@Before
	public void setUp() throws Exception {
		clsGenerator=ClassGeneratorFactory.getClassGenerator();
		assertNotNull(clsGenerator);
	}

	protected ClassObject createClass() {
		counter++;
		int index=counter;
		LineFactory lineFactory=clsGenerator.lineFactory;
		
		String subpackage=this.getClass().getPackage().getName().substring(this.getClass().getPackage().getName().lastIndexOf('.')+1);
		ClassObject cls=clsGenerator.objectFactory.classes.createClass("test.bidimensional."+subpackage+".LocalVariableTestClass"+index);
		cls.setSuperClass(MethodClass.class);
		
		
		FieldObject<Integer> fld1=clsGenerator.objectFactory.fields.createField("instanceVar", int.class);
		FieldObject<Long> fld1b=clsGenerator.objectFactory.fields.createField("instanceVar2", long.class);
		FieldObject<MethodClass> fld1c=clsGenerator.objectFactory.fields.createField("instanceObjVar", MethodClass.class);
		FieldObject<Integer> fld2=clsGenerator.objectFactory.fields.createField("staticVar", int.class);
		FieldObject<Long> fld2b=clsGenerator.objectFactory.fields.createField("staticVar2", long.class);
		FieldObject<MethodClass> fld2c=clsGenerator.objectFactory.fields.createField("staticObjVar", MethodClass.class);
		FieldObject<TestObj> fld3=clsGenerator.objectFactory.fields.createField("instanceObj", TestObj.class);
		FieldObject<TestObj> fld4=clsGenerator.objectFactory.fields.createField("staticObj", TestObj.class);
		
		fld1.setValue(4);
		fld1b.setValue(5l);
		fld1c.setInitialize(true);
		fld1c.setInitializationParams(new ParameterObject<?>[]{new ParameterObject<Integer>("p1", int.class, 4)});
		
		fld2.setValue(6);
		fld2b.setValue(7l);
		fld2c.setInitialize(true);
		fld2c.setInitializationParams(new ParameterObject<?>[]{new ParameterObject<Integer>("p1", int.class, 6)});

		fld2.setModifiers(new int[] {Opcodes.ACC_STATIC});
		fld2b.setModifiers(new int[] {Opcodes.ACC_STATIC});
		fld2c.setModifiers(new int[] {Opcodes.ACC_STATIC});
		fld4.setModifiers(new int[] {Opcodes.ACC_STATIC});
		
		fld3.setInitialize(true);
		fld4.setInitialize(true);
		
		cls.getFields().add(fld1);
		cls.getFields().add(fld1b);
		cls.getFields().add(fld1c);
		cls.getFields().add(fld2);
		cls.getFields().add(fld2b);
		cls.getFields().add(fld2c);
		cls.getFields().add(fld3);
		cls.getFields().add(fld4);
		
		//override default constructor
		ConstructorObject consObject=clsGenerator.objectFactory.constructors.createConstructor();
		consObject.setCode(lineFactory.methods.invokeSuperConstructor());
		cls.getConstructors().add(consObject);
		
		
		return cls;
	}
	
	
	public static class MethodClass implements MethodIface
	{
		private int value;
		
		public MethodClass() {}
		public MethodClass(int v)
		{
			this.value=v;
		}
		
		public int[][] createArray()
		{
			return new int[][] {{2,4,6},
								{3,5,7},
								{4,6,8}};
		}
		
		public Integer[][] createObjArray()
		{
			return new Integer[][] {{Integer.valueOf(2), Integer.valueOf(4), Integer.valueOf(6)},
									{Integer.valueOf(3), Integer.valueOf(5), Integer.valueOf(7)},
									{Integer.valueOf(4), Integer.valueOf(6), Integer.valueOf(8)}};
		}
		
		public MethodClass[][] createObjMArray()
		{
			return new MethodClass[][] {{new MethodClass(2), new ExtendedMethodClass(2), new MethodClass(6)},
										{new MethodClass(3), new ExtendedMethodClass(3), new MethodClass(7)},
										{new MethodClass(4), new ExtendedMethodClass(4), new MethodClass(8)}};
		}
		
		public static int[][] createStaticArray()
		{
			return new int[][] {{2,4,6,8}, {3,5,7,9}};
		}
		
		public static Integer[][] createStaticObjArray()
		{
			return new Integer[][] {{Integer.valueOf(2), Integer.valueOf(4), Integer.valueOf(6), Integer.valueOf(8)},
									{Integer.valueOf(3), Integer.valueOf(5), Integer.valueOf(7), Integer.valueOf(9)}};
		}
		public static MethodClass[][] createStaticObjMArray()
		{
			return new MethodClass[][] {{new MethodClass(2), new MethodClass(4), new ExtendedMethodClass(3), new MethodClass(8)},
										{new MethodClass(3), new MethodClass(5), new ExtendedMethodClass(4), new MethodClass(9)}};
		}
		
		public int getValue()
		{
			return value;
		}
		@Override
		public boolean equals(Object obj)
		{
			if(obj==null || !(obj instanceof MethodClass))
				return false;
			
			return value==((MethodClass)obj).value;
		}	
		
		@Override
		public int hashCode() {
			return Integer.valueOf(value).hashCode();
		}	
	}
	
	public static interface MethodIface
	{
		public int getValue();
	}
	
	public static class ExtendedMethodClass extends MethodClass
	{
		public ExtendedMethodClass() {}
		public ExtendedMethodClass(int v)
		{
			super(v*2);
		}
	}
	
	public static final class TestObj
	{
		public int instanceValue=50;
		public Integer instanceObjValue=Integer.valueOf(50);
		public MethodClass instanceObjVarValue=new MethodClass(50);
		public long instanceValue2=51l;
		
		public static int staticValue=100;
		public static Integer staticObjValue=Integer.valueOf(100);
		public static MethodClass staticObjVarValue=new MethodClass(100);
		public static double staticValue2=101.6d;
	}
}
